Warning: This document is for the development version of AutoGIS.

This page was generated from source/notebooks/L5/interactive-map-folium.ipynb.
Binder badge
Binder badge CSC badge

Interactive maps on Leaflet

Whenever you go into a website that has some kind of interactive map, it is quite probable that you are wittnessing a map that has been made with a JavaScipt library called Leaflet (the other popular one that you might have wittnessed is called OpenLayers.

There is also a Python module called Folium that makes it possible visualize data that’s been manipulated in Python on an interactive Leaflet map.

Creating a simple interactive web-map

Let’s first see how we can do a simple interactive web-map without any data on it. We just visualize OpenStreetMap on a specific location of the a world.

  • First thing that we need to do is to create a Map instance. There are few parameters that we can use to adjust how in our Map instance that will affect how the background map will look like.
  • See documentation of class folium.folium.Map() for all avaiable options.
In [44]:
import folium

# Create a Map instance
m = folium.Map(location=[60.25, 24.8],
    zoom_start=10, control_scale=True)

The first parameter location takes a pair of lat, lon values as list as an input which will determine where the map will be positioned when user opens up the map. zoom_start -parameter adjusts the default zoom-level for the map (the higher the number the closer the zoom is). control_scale defines if map should have a scalebar or not.

  • Let’s see what our map looks like:
In [45]:
m
Out[45]:
  • We can also save the map already now
  • Let’s save the map as a html file base_map.html:
In [46]:
outfp = "base_map.html"
m.save(outfp)

Navigate to the location where you saved the html file and open it in a web browser (preferably Google Chrome) to see the output.

  • Let’s change the basemap style to Stamen Toner and change the location of our map slightly. The tiles -parameter is used for changing the background map provider and map style (see the documentation for all possible ones).
In [47]:
# Let's change the basemap style to 'Stamen Toner'
m = folium.Map(location=[40.730610, -73.935242], tiles='Stamen Toner',
                zoom_start=12, control_scale=True, prefer_canvas=True)

m
Out[47]:
  • let’s also save this map as a html file:
In [48]:
# Filepath to the output
outfp = "base_map2.html"

# Save the map
m.save(outfp)

Task

Let’s take a few moments and play around with the parameters. Save the map and see how those changes affect the look of the map.

Adding layers to the map

Adding layers to a web-map is fairly straightforward and similar procedure as with Bokeh and we can use familiar tools to handle the data, i.e. Geopandas. Our ultimate aim is to create a plot like this where population in Helsinki and the address points are plotted on top of a web-map:

Let’s first practice by adding the address points onto the Helsinki basemap: - read input points using Geopandas:

In [49]:
import geopandas as gpd

# File path
points_fp = r"dataE5/addresses.shp"

# Read the data
points = gpd.read_file(points_fp)

#Check input data
points.head()
Out[49]:
address id geometry
0 Kampinkuja 1, 00100 Helsinki, Finland 1001 POINT (24.9301701 60.1683731)
1 Kaivokatu 8, 00101 Helsinki, Finland 1002 POINT (24.9418933 60.1698665)
2 Hermanstads strandsväg 1, 00580 Helsingfors, F... 1003 POINT (24.9774004 60.18735880000001)
3 Itäväylä, 00900 Helsinki, Finland 1004 POINT (25.0919641 60.21448089999999)
4 Tyynenmerenkatu 9, 00220 Helsinki, Finland 1005 POINT (24.9214846 60.1565781)
In [ ]:

In [ ]:
# Convert points to GeoJson
#points_gjson = folium.features.GeoJson(points.to_json())
points_gjson = folium.features.GeoJson(points)
In [ ]:
Now we have our population data stored in the ``pop_json`` variable as GeoJSON format which basically contains the
data as text in a similar way that it would be written in the ``.geojson`` -file.
  • add the points onto the Helsinki basemap
In [50]:
# Create a Map instance
m = folium.Map(location=[60.25, 24.8], tiles = 'cartodbpositron', zoom_start=11, control_scale=True)

# Add points to the map instance
points_gjson.add_to(m)

# Alternative syntax for adding points to the map instance
#m.add_child(points_gjson)

#Show map
m
Out[50]:

Choroplet map

Next, let’s check how we can overlay a population map on top of a basemap using folium’s choropleth method. This method is able to read the geometries and attributes directly from a geodataframe. This example is modified from the Folium quicksart.

  • First, read in the population grid:
In [51]:
# Filepaths
fp = "dataE5/Vaestotietoruudukko_2015.shp"

# Read Data
data = gpd.read_file(fp)

# Check the data
data.head()
Out[51]:
INDEX ASUKKAITA ASVALJYYS IKA0_9 IKA10_19 IKA20_29 IKA30_39 IKA40_49 IKA50_59 IKA60_69 IKA70_79 IKA_YLI80 geometry
0 688 8 31.0 99 99 99 99 99 99 99 99 99 POLYGON ((25472499.99532626 6689749.005069185,...
1 703 6 42.0 99 99 99 99 99 99 99 99 99 POLYGON ((25472499.99532626 6685998.998064222,...
2 710 8 44.0 99 99 99 99 99 99 99 99 99 POLYGON ((25472499.99532626 6684249.004130407,...
3 711 7 64.0 99 99 99 99 99 99 99 99 99 POLYGON ((25472499.99532626 6683999.004997005,...
4 715 19 23.0 99 99 99 99 99 99 99 99 99 POLYGON ((25472499.99532626 6682998.998461431,...
  • re-project layer into WGS 84 (epsg: 4326)
  • Modify columns:
In [52]:
# Re-project to WGS84
data = data.to_crs(epsg=4326)

# Check layer crs definition
print(data.crs)

# Make a selection (only data above 0 and below 1000)
data = data.loc[(data['ASUKKAITA'] > 0) & (data['ASUKKAITA'] <= 1000)]

# Create a Geo-id which is needed by the Folium (it needs to have a unique identifier for each row)
data['geoid'] = data.index.astype(str)

# Select only needed columns
data = data[['geoid', 'ASUKKAITA', 'geometry']]

# Convert to geojson (not needed for the simple coropleth map!)
#pop_json = data.to_json()

#check data
data.head()
{'init': 'epsg:4326', 'no_defs': True}
Out[52]:
geoid ASUKKAITA geometry
0 0 8 POLYGON ((24.50236241370834 60.31927864851716,...
1 1 6 POLYGON ((24.50287385337343 60.28562263749414,...
2 2 8 POLYGON ((24.50311210582754 60.26991652312412,...
3 3 7 POLYGON ((24.50314612020954 60.26767278939882,...
4 4 19 POLYGON ((24.50328212493893 60.25869775697638,...
In [53]:
# Create a Map instance
m = folium.Map(location=[60.25, 24.8], tiles = 'cartodbpositron', zoom_start=10, control_scale=True)

# Plot a choropleth map
# Notice: 'geoid' column that we created earlier needs to be assigned always as the first column
m.choropleth(
    geo_data=data,
    name='choropleth',
    data=data,
    columns=['geoid', 'ASUKKAITA'],
    key_on='feature.id',
    fill_color='YlOrRd',
    fill_opacity=0.7,
    line_opacity=0.2,
    line_color='white',
    line_weight=0,
    highlight=False,
    smooth_factor=1.0,
    #threshold_scale=[100, 250, 500, 1000, 2000],
    legend_name= 'Population in Helsinki')

#Show map
m
Out[53]:

Clustered point map

In [ ]: